/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.activity.helper;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.ActivityParameterNode;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;

import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Manages an ActivityParameterNode
 *
 * @author Gilles Cannenterre
 * @since 27 mars 07
 */
public class NodeActivityParameterNodeHelper extends NodeActivityNodeHelper {

	/**
	 * The default container. 
	 */
	private GraphElement defaultContainer;

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.NodeHelper#createUMLElement(java.lang.String, org.eclipse.uml2.uml.Element)
	 */
	@Override
	public Element createUMLElement(String name, Element umlParent){
		
		ActivityParameterNode anObject = (ActivityParameterNode) super.createUMLElement(name, umlParent);

		if (umlParent instanceof Activity) {		
			LiteralUnlimitedNatural thenatural=UMLFactory.eINSTANCE.createLiteralUnlimitedNatural();
			thenatural.setValue(LiteralUnlimitedNatural.UNLIMITED);
			anObject.setUpperBound(thenatural);
		}
		
		return anObject;
	}
	
	protected EClass getNodeType() {
		return UMLPackage.eINSTANCE.getCentralBufferNode();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.NodeHelper#getBaseString()
	 */
	@Override
	public String getBaseString() {
		return "ActivityParameterNode_"; //$NON-NLS-1$
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.INodeFactory#createGraphNode()
	 */
	@Override
	public GraphNode createGraphElement(Element umlChild, GraphElement parent, Point location, Dimension size){
		defaultContainer = parent.getContainer();
		// graph element must be added to the parent graph element (specific to activity parameter node)
		GraphNode node = super.createGraphElement(umlChild, parent.getContainer(), location, size);
		Point newpos= new Point(0,0);
	
		newpos=LookForElement.calculateAbsolutePosition((GraphNode)parent, location);
	
		//to say that the port belogn to entity parent
		node.setSemanticParent(parent);
		// set defaut size, if null
		node.setSize(getGraphNodeSize());
	
		// set correct position: calculate position for the activity parameter node
		node.setPosition(inRunner((GraphNode)parent, newpos, node.getSize()));
		Point origin=LookForElement.calculateAbsolutePosition(((GraphNode)parent.getContainer()),new Point(0,0));
		node.setPosition(node.getPosition().getTranslated(origin.getNegated().getCopy()));
		
		return node;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.NodeHelper#removeGraphElement(com.cea.papyrus.core.diagraminterchange2.di2.GraphElement, com.cea.papyrus.core.diagraminterchange2.di2.GraphElement)
	 */
	@Override
	public boolean removeGraphElement(GraphElement child, GraphElement parent){
		// Save the default container for undo command...
		defaultContainer = child.getContainer();
		child.setSemanticParent(null);
		child.eAdapters().clear();
		if (child.getContainer() != null) {
			child.getContainer().getContained().remove(child);
		}
		return true;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.NodeHelper#addGraphElement(com.cea.papyrus.core.diagraminterchange2.di2.GraphElement, com.cea.papyrus.core.diagraminterchange2.di2.GraphElement)
	 */
	@Override
	public GraphElement addGraphElement(GraphElement child, GraphElement parent) {
		child.setSemanticParent(parent);
		if (child.getSemanticParent().getContainer() != null) {
			child.getSemanticParent().getContainer().getContained().add(child);
		} else {
			defaultContainer.getContained().add(child);
		}
		return child;
	}
	
	/**
	 * this method calculate the good position of a port by taking account of his parent.
	 * 
	 * @param portDimension the dimension of the port
	 * @param parentGP graphNode the virtual graphNode that contains the port
	 * @param point the absolute position
	 * 
	 * @return the new position of the port.
	 */
	public Point inRunner(GraphNode parentGP,Point point, Dimension portDimension){
		int x= point.x;
		int y= point.y;
		Point selected =point.getCopy();
		//calculate absolute position of GP


		Point positionGP=LookForElement.calculateAbsolutePosition(parentGP,new Point(0,0));


		// position is constraint in the parent rectangle
		if (x<positionGP.x-portDimension.width/2){
			x=positionGP.x-portDimension.width/2;
		}
		if (x>positionGP.x+parentGP.getSize().width-portDimension.width/2){
			x=positionGP.x+parentGP.getSize().width-portDimension.width/2;
		}

		if (y<positionGP.y-portDimension.height/2){
			y=positionGP.y-portDimension.height/2;
		}
		if (y>positionGP.y+parentGP.getSize().height-portDimension.height/2){
			y=positionGP.y+parentGP.getSize().height-portDimension.height/2;
		}

		//calculte all 4 possible positions.		
		Point pointWEST= new Point(positionGP.x-portDimension.width/2, y);
		Point pointNORTH= new Point(x,positionGP.y-portDimension.height/2);
		Point pointEAST= new Point(positionGP.x+parentGP.getSize().width-portDimension.width/2, y);
		Point pointSOUTH= new Point(x,positionGP.y+parentGP.getSize().height-portDimension.height/2);

		// calculate all distance
		double distanceWEST=pointWEST.getDistance(point);
		double distanceNORTH=pointNORTH.getDistance(point);
		double distanceEAST=pointEAST.getDistance(point);
		double distanceSOUTH=pointSOUTH.getDistance(point);
		Debug.debug(this,"pointWEST: "+pointWEST+" "+distanceWEST,channel);
		Debug.debug(this,"pointNORTH: "+pointNORTH+" "+distanceNORTH,channel);
		Debug.debug(this,"pointEAST: "+pointEAST+" "+distanceEAST,channel);
		Debug.debug(this,"pointSOUTH: "+pointSOUTH+" "+distanceSOUTH,channel);

		//choose the point the minimum distance
		selected=pointWEST;
		double selecteddistance=distanceWEST;
		if (selecteddistance>distanceNORTH){
			selected=pointNORTH;
			selecteddistance=distanceNORTH;}

		if (selecteddistance>distanceEAST){
			selected=pointEAST;
			selecteddistance=distanceEAST;}

		if (selecteddistance>distanceSOUTH){
			selected=pointSOUTH;
			selecteddistance=distanceSOUTH;}
		Debug.debug(this,"miminmum distance: "+selected+" "+selecteddistance,channel);
		
		return selected;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.NodeHelper#getGraphNodeSize()
	 */
	@Override
	public Dimension getGraphNodeSize() {
		return new Dimension(180,50);
	}
}
